package com.stars.module.menu.service.impl;

import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.stars.base.constants.CommonNumberConstants;
import com.stars.base.constants.RedisConstants;
import com.stars.base.constants.SeparatorConstants;
import com.stars.base.entity.CommonDTO;
import com.stars.base.entity.SessionUser;
import com.stars.base.entity.TreeNode;
import com.stars.base.exception.BaseException;
import com.stars.module.menu.entity.MenuEntity;
import com.stars.module.menu.entity.StarMenu;
import com.stars.module.menu.entity.StarMenuVo;
import com.stars.module.menu.mapper.StarMenuMapper;
import com.stars.module.menu.service.StarMenuService;
import com.stars.util.cache.CacheUtil;
import com.stars.util.common.Assert;
import com.stars.util.common.DevelopKit;
import com.stars.util.tree.TreeNodeUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.*;

/**
 * @author : Rocks
 * @version : 1.0
 * @date : 2022/11/8 10:26
 * @description : 菜单服务实现类
 */
@Service
public class StarMenuServiceImpl implements StarMenuService {

    private final StarMenuMapper menuMapper;
    private final CacheUtil cacheUtil;

    public StarMenuServiceImpl(StarMenuMapper menuMapper, CacheUtil cacheUtil) {
        this.menuMapper = menuMapper;
        this.cacheUtil = cacheUtil;
    }

    @Override
    public boolean saveOrUpdateMenu(StarMenuVo vo) {

        boolean result;

        StarMenu menu = new StarMenu();
        BeanUtils.copyProperties(vo, menu);
        menu.setPermission(String.join(",", vo.getPermissionList()));

        if(StringUtils.hasLength(menu.getId())){
            //有ID，更新
            result = menuMapper.updateById(menu) > 0;
        }else{
            //无ID，新增
            menu.setId(DevelopKit.generateUUID());

            DevelopKit.setBaseInfo(menu);

            result = menuMapper.insert(menu) > 0;
        }
        cacheUtil.clearCache(RedisConstants.MENU_PREFIX);
        return result;
    }

    @Override
    public boolean removeMenu(String id) {

        LambdaQueryWrapper<StarMenu> query = new LambdaQueryWrapper<>();
        query.eq(StarMenu::getFid,id);

        if(menuMapper.exists(query)){
            return false;
        }

        boolean result = menuMapper.deleteById(id) > 0;

        cacheUtil.clearCache(RedisConstants.MENU_PREFIX);

        return result;
    }

    @Override
    public StarMenuVo loadMenuById(String id) {
        StarMenuVo vo = new StarMenuVo();
        StarMenu starMenu = menuMapper.selectById(id);
        BeanUtils.copyProperties(starMenu,vo);
        vo.setPermissionList(Collections.emptyList());
        if (StringUtils.hasLength(starMenu.getPermission())) {
            vo.setPermissionList(Arrays.asList(starMenu.getPermission().split(",")));
        }
        return vo;
    }

    @Override
    public JSONObject loadMenuByFid(CommonDTO search) {

        Page<StarMenu> page = Page.of(search.getCurrent(), search.getPageSize());

        LambdaQueryWrapper<StarMenu> query = new LambdaQueryWrapper<>();
        query
                .eq(StarMenu::getFid, search.getFid())
                .and(
                        wrapper -> wrapper
                                .like(StarMenu::getMenuName,search.getSearch())
                                .or()
                                .like(StarMenu::getAction,search.getSearch())
                )
                .orderByAsc(StarMenu::getShowOrder);

        Page<StarMenu> starMenuPage = menuMapper.selectPage(page, query);

        JSONObject result = new JSONObject();

        result.put("list",starMenuPage.getRecords());
        result.put("total",starMenuPage.getTotal());

        return result;
    }

    @Override
    public List<MenuEntity> loadMenuByUser() throws BaseException {

        List<StarMenu> allMenus = this.getUserMenuList();

        Map<String,MenuEntity> map = new HashMap<>();

        List<String> list = new ArrayList<>();
        for(StarMenu starMenu : allMenus){

            MenuEntity entity = new MenuEntity();

            entity.setId(starMenu.getId());
            entity.setFid(starMenu.getFid());
            entity.setIcon(starMenu.getIcon());
            entity.setName(starMenu.getMenuName());
            entity.setAction(starMenu.getAction());
            entity.setTarget(starMenu.getTarget());
            entity.setChildren(new ArrayList<>());

            map.put(starMenu.getId(), entity);
            if(CommonNumberConstants.ZERO_STR.equals(starMenu.getFid())){
                list.add(starMenu.getId());
            }
        }

        for(StarMenu starMenu : allMenus){
            if(map.containsKey(starMenu.getFid())){
                map.get(starMenu.getFid()).getChildren().add(map.get(starMenu.getId()));
            }
        }

        List<MenuEntity> result = new ArrayList<>();

        for(String id : list){
            result.add(map.get(id));
        }

        return result;
    }

    private List<StarMenu> getUserMenuList () throws BaseException {

        SessionUser user = DevelopKit.getSessionUser();

        Assert.isNotNull(user, "当前登录信息失效！");

        List<StarMenu> allMenus;

        // 判断用户菜单在redis中是否存在，如果存在则直接返回redis中数据
        String key = RedisConstants.MENU_PREFIX + user.getUserId();

        allMenus = cacheUtil.getValueByList(false, key, StarMenu.class);

        if (allMenus != null && !allMenus.isEmpty()) {
            return allMenus;
        }

        // redis中不存在用户菜单数据，从数据库查询菜单，并且将菜单存入redis
        LambdaQueryWrapper<StarMenu> query = new LambdaQueryWrapper<>();
        query.orderByAsc(StarMenu::getShowOrder);

        query.eq(StarMenu::getPermission,"").or().in(StarMenu::getPermission,Arrays.asList(user.getPrivileges().split(SeparatorConstants.COMMA_SEPARATOR)));

        allMenus = menuMapper.selectList(query);

        cacheUtil.setValue(false, key, allMenus);

        return allMenus;
    }

    @Override
    public JSONArray loadAllMenu() {

        JSONArray array = new JSONArray();
        LambdaQueryWrapper<StarMenu> query = new LambdaQueryWrapper<>();
        query.orderByAsc(StarMenu::getShowOrder);

        List<StarMenu> allMenus = menuMapper.selectList(query);
        List<TreeNode> treeNodes = new ArrayList<>();

        for(StarMenu menu : allMenus){

            TreeNode node = new TreeNode();
            node.setValue(menu.getId());
            node.setpId(menu.getFid());
            node.setLabel(menu.getMenuName());

            treeNodes.add(node);

        }

        TreeNode root = new TreeNode(CommonNumberConstants.ZERO_STR,"菜单管理",CommonNumberConstants.MINUS_ONE_STR);

        array.add(TreeNodeUtil.merge(root,treeNodes).toJSON());

        return array;
    }

    @Override
    public int getMaxIndex(String fid) {
        return menuMapper.getMaxIndex(fid);
    }
}
